#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<map>
#include<array>
#include<functional>
using namespace std;

#include<assert.h>
#include"vector.h"

struct Point
{
	int _x;
	int _y;
};


class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

//一切都可以使用列表初始化，并且可以省略掉=
void test1()
{
	int x = 0;
	int y = { 0 };
	int y1{ 0 };

	int arr1[5] = { 1,2,3,4,5 };
	int arr2[]{ 1,2,3,4,5 };
	int arr3[5]{ 0 };

	Point t = { 1,2 };
	Point t1{ 1,2 };

	// 类型转换  构造+拷贝构造->优化直接构造
	Date d1 = { 2024,8,25 };
	Date d2 = { 2024,8,24 };
	Date d3 = { 2024,8,23 };
	
	const Date& d4 = { 1,2,3 };

	Date* p1 = new Date[3]{ d1,d2,d3 };
	Date* p2 = new Date[3]{ {2024,8,25},{2024,8,24},{2024,8,23} };


}

//the type of il is an initializer_list
void test2()
{
	//调用initailizer_list的构造函数，参数可变
	vector<int> v = { 1,2,3,4,5,6 };

	//隐式类型转换的构造函数
	// 跟对应构造函数参数个数匹配
	Date d2 = { 1,2,3 };

	//initializer_list内部有两个指针，一个指向起始的第一个位置，一个指向结束的位置
	auto il1 = { 10, 20, 30, 40, 50 };
	cout << typeid(il1).name() << endl;
	
	//支持迭代器
	initializer_list<int> il2 = { 10, 20, 30};
	initializer_list<int>::iterator it2 = il2.begin();
	while (it2 != il2.end())
	{
		cout << *it2 << " ";
		++it2;
	}
	cout << endl;

	//for (int e : il2)
	for (auto e : il2)
	{
		cout << e << " ";
	}
	cout<< endl;

	pair<string, string> kv1("sort", "排序");
	map<string, string> dict = {{"insert", "插入"}, {"get","获取"} };
	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}

	cyq::vector<int> v2 = { 1,2,3,4,54 };
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
	
	
}

//typeid和decltype
class A
{
private:
	decltype(malloc) pf2;
};

template<class Func>
class B
{
private:
	Func _f;
};

void test3()
{
	int a = 10;
	auto p = &a;
	auto p1 = malloc;

	//typeid推出类型是一个字符串，只能看不能用
	cout << typeid(a).name() << endl;
	cout << typeid(p).name() << endl;
	cout << typeid(p1).name() << endl;


	// decltype推出对象的类型，再定义变量，或者作为模板实参
	// 单纯先定义一个变量出现
	decltype(p1) pf2;

	B<decltype(p1)> bb1;

	const int x = 1;
	double y = 2.2;

	B<decltype(x * y)> bb2;

}

int func(int a, int b)
{
	return a < b ? a : b;
}

//右值引用
void test4()
{
	//左值--可以取地址，可以修改
	int a = 10;
	int* ptr = new int(0);
	const int c = 2;
	"xxxxx";
	const char* p = "xxxxx";
	p[2];
	int x = 10;
	int y = 20;

	//右值--不可以取地址，不可以修改
	10;  //常量
	x + y;  //表达式返回值
	func(x, y);  //函数返回值

}

//右值引用--给右值取别名
//左值引用--给左值取别名
void test5()
{
	//左值引用
	int b = 10;
	int& a = b;
	int* ptr = new int(1);
	int* &p = ptr;
	const int c = 2;
	const int& d = c;
	const char* str = "xxxxx";
	const char* & s = str;

	//右值引用
	int&& r1 = 10;
	int&& r2 = a + b;
	int&& r3 = func(a, b);

	//const修饰的左值引用可以作为右值的别名
	const int& r4 = 10;
	const int& r5 = func(a, b);
	const int& r6 = a + b;

	//右值引用可以给move后的左值取别名
	int&& m1 = move(b);
	const char*&& m2 = move(str);
	const int*&& m3 = move(ptr);
}

namespace cyq
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(const char* str)" << endl;

			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		// s1.swap(s2)
		//s如果是右值就不能修改了
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		// 拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;

			//string tmp(s._str);
			//swap(tmp);
		}

		string(string&& s)
			:_str(nullptr)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;

			//为了支持交换，s必须是左值
			swap(s);
		}

		// 赋值重载
		string& operator=(const string& s)
		{
			cout << "string& operator=(string s) -- 深拷贝" << endl;
			//string tmp(s);
			//swap(tmp);

			return *this;
		}

		string& operator=(string && s)
		{
			cout << "string& operator=(string && s) -- 移动拷贝" << endl;
			swap(s);

			return *this;
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;

				_capacity = n;
			}
		}

		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}

			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}

		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		const char* c_str() const
		{
			return _str;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的\0
	};
}

//不能使用引用返回，会导致野引用的问题
cyq::string func1()
{
	cyq::string temp("xxxxxxxxxxxxxxxxxxxxx");

	return temp;
}

//右值引用的第一个使用场景--弥补左值引用的缺陷：当返回值为自定义类型时减少拷贝
void test6()
{
	//首先，编译器会优化：拷贝构造+拷贝构造-->拷贝构造
	//没有移动构造的情况下会调用一次深拷贝
	//有移动构造的情况下，编译器会将temp识别为右值（将亡值）,调用移动拷贝
	cyq::string s1 = func1();

	//构造函数
	cyq::string s2;
	//拷贝构造+赋值
	//没有移动构造的情况下会调用两次深拷贝
	//有移动构造的情况下会调用两次移动拷贝
	s2 = func1();

	std::string ret3("1111111111111111111111111111");
	std::string copy1 = ret3;
	move(ret3);
	std::string copy2 = ret3; // 拷贝构造
	std::string copy3 = move(ret3); // 移动构造
}

// 构成函数重载 
//可以接收右值和左值
void func(const int& r)
{
	cout << "void func(const int& r)" << endl;
}

//只能接收左值
void func(int&& r)
{
	cout << "void func(int&& r)" << endl;
}

void test7()
{
	int a = 0;
	int b = 1;
	func(a);

	// 走更匹配的，有右值引用的重载，就会走右值引用版本
	func(a + b);

}

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }

void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

// 万能引用：既可以接收左值，又可以接收右值
// 实参左值，他就是左值引用（引用折叠）
// 实参右值，他就是右值引用
template<typename T>
//t编译器会认为它是左值--可以修改
void PerfectForward(T&& t)
{
	// 完美转发，t是左值引用，保持左值属性
	// 完美转发，t是右值引用，保持右值属性
	Fun(forward<T>(t));
	//Fun(t);

}

void test8()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);		      // const 左值
	PerfectForward(std::move(b)); // const 右值

}

//list中的右值引用和完美转发
//右值引用的第二个使用场景--当插入数据是右值的时候，可以调用对象的移动拷贝来完成数据结构的构造
#include"list.h"
#include"string.h"

void test9()
{
	cyq::list<cyq::string> lt;  //哨兵位头结点-->构造+拷贝构造-->移动拷贝
	cyq::string s1("111111111111111111111");  //构造
	lt.push_back(s1);  //拷贝构造-->深拷贝

	cout << endl << endl;
	cyq::string s2("111111111111111111111");  //构造
	lt.push_back(move(s2));  //拷贝构造-->移动拷贝

	cout << endl << endl;
	lt.push_back("22222222222222222222222222222");  //匿名对象的构造（生命周期只在当前行，属于将亡值）+拷贝构造-->移动拷贝
}

//lambda函数
void test10()
{
	int x = 0;
	int y = 1;
	int a = 2;
	int b = 3;
	int c = 4;
	int d = 5;

	//传值捕捉--传进来的是x和y的拷贝
	auto p1 = [x, y]() {
		//lambda函数默认为const函数，x和y不能修改
		//x++;
		//y++;
		return x + y; };
	cout << p1() << endl;

	//mutable可以改变x和y的属性
	auto p2 = [x, y] ()mutable {
		//lambda函数默认为const函数，x和y不能修改
		x++;
		y++;
		return x + y; };
	cout << p2() << endl;

	//传址捕捉
	auto p3 = [&x, &y](){
		//lambda函数默认为const函数，x和y不能修改
		int temp = x;
		x = y;
		y = temp;
		cout << x  << " " << y << endl; };
	p3();

	//传址捕捉父作用域的全部可使用变量
	auto p4 = [&]() {
		a++;
		b++;
		c++;
		d++;
		cout << a << " " << b << " " << c << " " << d << endl;
		};
	p4();

	//传值捕捉父作用域的全部可使用变量
	auto p5 = [=]() {
		//a++;
		//b++;
		//c++;
		//d++;
		cout << a << " " << b << " " << c << " " << d << endl;
		};
	p5();

	//[=, &a, &b]：以引用传递的方式捕捉变量a和b，值传递方式捕捉其他所有变量
	auto p6 = [=,&a,&b]() {
		a++;
		b++;
		//c++;
		//d++;
		cout << a << " " << b << " " << c << " " << d << endl;
		};
	p6();

	//[=, a] ： = 已经以值传递方式捕捉了所有变量，捕捉a重复
	//lambda函数的底层是一个仿函数，pn实际上是一个用这个类创建出来的一个对象，相互之间不能赋值，因为他们的类型不同
	//如果定义了一个lambda表达式，编译器会自动生成一个类，在该类中重载了operator()。
	//p1 = p2;
	//在块作用域以外的lambda函数捕捉列表必须为空
}

//模板的可变参数
void CppPrint()
{
}

template<class T,class ... Args>
void CppPrint(T val, Args ... args)
{
	cout << val << " ";
	CppPrint(args...);
}

template<class ... Args>
void _CppPrint( Args ... args)
{
	CppPrint(args...);
}

void test11()
{
	//模拟printf可变参数的打印
	//递归展开参数包
	_CppPrint();
	cout << endl;
	_CppPrint(1);
	cout << endl;
	_CppPrint(1,2.2);
	cout << endl;
	_CppPrint(1,2.2,"xxxxxx");
	cout << endl;
}

template<class T>
void showlist(T val)
{
	cout << val << " ";
}

template<class ... Args>
void ShowList(Args...args)
{
	int a[] = { (showlist(args),0)... };
}

void test12()
{
	//模拟printf可变参数的打印
	//逗号表达式展开参数包
	ShowList(1);
	cout << endl;
	ShowList(1, 2.2);
	cout << endl;
	ShowList(1, 2.2, "xxxxxx");
	cout << endl;
}

//构造/拷贝构造函数中的参数包
class Date2
{
public:
	Date2(int  year = 1, int month = 1,int day=1 )
		:_year(year)
		,_month(month)
		,_day(day)
	{
		cout << "Date的构造函数" << endl;
	}

	Date2(const Date2& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date的拷贝构造函数" << endl;
	}

private:
	int _year;
	int _month;
	int _day;

};

//灵活：可以使用多种形式的参数进行Date类的构造或拷贝构造
template<class ...Args>
Date2* Creat(Args...args)
{
	Date2* ret = new Date2(args...);
	return ret;
}
void test13()
{
	Creat(2023);
	Creat(2023,10);
	Creat(2023,10,22);
	Creat();

	Date2 d1;
	Creat(d1);

	Creat(Date2(2024, 8, 25));

}

//list中的emplace和push_back
//emplace_back支持可变参数，拿到构建pair对象的参数后自己去创建对象
void test14()
{
	std::list<pair<int, cyq::string>> lt;
	//构造+拷贝构造-->移动拷贝
	lt.push_back({ 1,"sort" });
	lt.push_back(make_pair(2, "insert"));

	//构造
	lt.emplace_back(3, "erase");
	lt.emplace_back(make_pair(4,"modify" ));

	std::list<Date2> lt1;
	Date2 d(2023, 9, 27);
	// 只能传日期类对象
	lt1.push_back(d);

	// 传日期类对象
	// 传日期类对象的参数包
	// 参数包，一路往下传，直接去构造或者拷贝构造节点中日期类对象
	lt1.emplace_back(d);
	lt1.emplace_back(2023, 9, 27);
	
}

//默认移动构造和默认移动赋值--没有显示写并且析构、拷贝构造、赋值运算符重载任意一个没有显示写
//就会调用编译器生成的默认移动构造和默认移动赋值--内置类型按字节进行浅拷贝，自定义类型去调用它内部的移动拷贝和移动赋值（没有的话就调用普通的拷贝构造和赋值）
class Person
{
public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _age(age)
	{}
	/*Person(const Person& p)
	:_name(p._name)
	,_age(p._age)
	{}*/

	/*Person& operator=(const Person& p)
	{
	if(this != &p)
	{
	_name = p._name;
	_age = p._age;
	}
	return *this;
	}*/

	//强制生产默认成员函数
	/*Person(Person&& p) = default;
	Person(const Person& p) = default;
	Person& operator=(const Person& p) = default;*/

	//强制禁止生成默认成员函数
	//Person(Person&& p) = delete;


	~Person()
	{}

private:
	cyq::string _name;
	int _age;
};

void test15()
{
	Person s1;
	Person s2 = s1;
	Person s3 = std::move(s1);
	Person s4;
	s4 = std::move(s2);
}

//包装器function
template<class T,class F>
T Func(F f, T val)
{
	static int count = 0;
	cout << ++count << endl;
	cout << &count << endl;

	return f(val);
}

double f(double x)
{
	cout << x / 3 << endl;
	return x / 3;
}

template<class T>
struct fstruct
{
	int operator()(T x)
	{
		cout << x / 3 << endl;
		return x / 3;
	}
};

//实例化出三份Func
void test16()
{
	//函数指针
	Func(f, 1.1);

	//函数对象
	Func(fstruct<double> (), 2.1);

	//lambda表达式
	Func([](double x) {cout << x / 3 << endl;  return x / 3; }, 3.1);


}

//包装器实现只实例化出一份Func
void test17()
{
	function<double(double)> func1 = f;
	function<double(double)> func2 = fstruct<double>();
	function<double(double)> func3 = [](double x) {cout << x / 3 << endl;  return x / 3; };

	//可以在容器中存储各种可调用对象
	vector< function<double(double)>> v = { func1,func2,func3 };
	double d = 1.1;
	for (auto& f : v)
	{
		Func(f, d);
	}

}

//绑定--适用于想要固定参数或者改变参数的场景
int sub(int a, int b)
{
	return a - b;
}

double mul(int a, int b, double rate)
{
	return rate * (a + b);
}

double mmul(double rate,int a,int b)
{
	return rate * (a + b);
}

class SubType
{
public:
	static int Sub(int a, int b)
	{
		return (a + b);
	}

	int SSub(int a, int b, int rate)
	{
		return rate * (a + b);
	}
};

void test18()
{
	//调整参数的位置
	//function<int(int,int)> func1 = bind(sub, placeholders::_1, placeholders::_2);  //5
	function<int(int, int)> func1 = bind(sub, placeholders::_2, placeholders::_1);  //-5
	cout << func1(10, 5) << endl;  

	//固定参数--固定后的参数不参与计算参数列表的位置
	function<double(int, int)> func2 = bind(mul, placeholders::_1, placeholders::_2, 4.0);
	function<double(int, int)>  func3 = bind(mul, placeholders::_1, placeholders::_2, 4.2);
	function<double(int, int)> func4 = bind(mul, placeholders::_1, placeholders::_2, 4.4);
	cout << func2(10, 5) << endl;
	cout << func3(10, 5) << endl;
	cout << func4(10, 5) << endl;

	function<double(int, int)> func5 = bind(mmul,4.4, placeholders::_1, placeholders::_2);
	cout << func5(10, 5) << endl;

	//类的成员函数的绑定
	//静态成员函数的调用不需要this指针，取地址可以加&也可以不加&
	function<int(int, int)> func6 = bind(&SubType::Sub, placeholders::_1, placeholders::_2);
	cout << func6(10, 5) << endl;

	//非静态成员函数的调用需要对象指针或者对象，取地址必须加&
	function<int(int, int)> func7 = bind(&SubType::SSub, SubType(), placeholders::_1, placeholders::_2, 3);
	cout << func7(10, 5) << endl;

	SubType st;
	function<int(int, int)> func8 = bind(&SubType::SSub, &st, placeholders::_1, placeholders::_2, 3);
	cout << func8(10, 5) << endl;

}

int main()
{
	test1();
	cout << "-----------------------------------------------------" << endl;

	test2();
	cout << "-----------------------------------------------------" << endl;

	test3();
	cout << "-----------------------------------------------------" << endl;

	test4();
	//cout << "-----------------------------------------------------" << endl;

	test5();

	test6();
	cout << "-----------------------------------------------------" << endl;

	test7();
	cout << "-----------------------------------------------------" << endl;

	test8();
	cout << "-----------------------------------------------------" << endl;

	test9();
	cout << "-----------------------------------------------------" << endl;

	test10();
	cout << "-----------------------------------------------------" << endl;

	test11();
	cout << "-----------------------------------------------------" << endl;

	test12();
	cout << "-----------------------------------------------------" << endl;

	test13();
	cout << "-----------------------------------------------------" << endl;

	test14();
	cout << "-----------------------------------------------------" << endl;

	test15();
	cout << "-----------------------------------------------------" << endl;

	test16();
	cout << "-----------------------------------------------------" << endl;

	test17();
	cout << "-----------------------------------------------------" << endl;

	test18();
	cout << "-----------------------------------------------------" << endl;
	return 0;
}